﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Windows.Threading;

namespace VBoxServiceMonitor
{
    /// <summary>
    /// Interface to Service-Executable.
    /// </summary>
    [ServiceContract]
    public interface IServiceStatus
    {
        [OperationContract]
        int getCurrentStatus();

        [OperationContract]
        bool setPowerMode(int iTargetMode);

        [OperationContract]
        bool mountDVD(bool bIsPhysical, string sTargetPath);

        [OperationContract]
        string getDriveStatus(string sController, string sPort, string sDevice);
    }

    /// <summary>
    /// Monitor-MainWindow-Dialog.
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// Monitor-Tray-Icon.
        /// </summary>
        System.Windows.Forms.NotifyIcon m_NotifyIcon;

        /// <summary>
        /// Browse-ISO-File for ODD-Control.
        /// </summary>
        System.Windows.Forms.OpenFileDialog dlgBrowseISO;

        /// <summary>
        /// Service-Configuration.
        /// </summary>
        VBoxService.Settings oSettings;

        /// <summary>
        /// Current Guest-Status (Powermode).
        /// </summary>
        int CurrentStatus = 0;

        /// <summary>
        /// Initialize new Dialog.
        /// </summary>
        public MainWindow()
        {
            // Build GUI.
            InitializeComponent();

            /************************************************
             * Initialice Vars
             * */
            oSettings = new VBoxService.Settings();
            oSettings.Load();

            // Set Window-Title.
            this.Title = Strings.T_AppTitle;
            btnExit.ToolTip = Strings.T_ExitInfo;
            btnRefresh.ToolTip = Strings.T_RefreshInfo;
            btnAbout.ToolTip = Strings.T_About;

            // Blank Values
            lblGuestName.Content = String.Empty;
            lblGuestStatus.Content = String.Empty;

            // Setup initial Tray-Icon.
            this.Visibility = System.Windows.Visibility.Hidden;
            m_NotifyIcon = new System.Windows.Forms.NotifyIcon();
            m_NotifyIcon.BalloonTipTitle = "VBoxService4Windows";
            m_NotifyIcon.DoubleClick += new EventHandler(m_NotifyIcon_DoubleClick);
            m_NotifyIcon.BalloonTipText = String.Format(Strings.T_TrayIconText, oSettings.VBoxGuestName, "unknown");
            m_NotifyIcon.Icon = new System.Drawing.Icon(VBoxService.Settings.getServiceBaseDir() + "unknown.ico");
            m_NotifyIcon.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info;
            m_NotifyIcon.Visible = true;

            imgStatus.Source = new BitmapImage(new Uri(VBoxService.Settings.getServiceBaseDir() + "unknown.png", UriKind.RelativeOrAbsolute));

            // Setup ISO-File-Browser.
            dlgBrowseISO = new System.Windows.Forms.OpenFileDialog();
            dlgBrowseISO.CheckFileExists = true;
            dlgBrowseISO.Filter = Strings.T_ISOImage + "|*.iso|" + Strings.T_AllFiles + "|*.*";
            dlgBrowseISO.FilterIndex = 0;
            dlgBrowseISO.Multiselect = false;
            dlgBrowseISO.RestoreDirectory = true;
            dlgBrowseISO.Title = Strings.T_SelectISOorPhysical;

            /************************************************
            * Update GUI
            * */
            lblGuestName.Content = oSettings.VBoxGuestName + "(@" + oSettings.ControlPort + ")";
            lblGuestStatus.Content = "-";
            updateStatus();

            /************************************************
            * Setup Update-Timer.
            * */
            DispatcherTimer oUpdateTimer = new DispatcherTimer();
            oUpdateTimer.Tick += new EventHandler(oUpdateTimer_Tick);
            oUpdateTimer.Interval = new TimeSpan(0, oSettings.UpdateInterval, 0);
            oUpdateTimer.Start();
        }

        void oUpdateTimer_Tick(object sender, EventArgs e)
        {
            updateStatus();
        }

        void m_NotifyIcon_DoubleClick(object sender, EventArgs e)
        {
            this.Show();
            this.WindowState = System.Windows.WindowState.Normal;
            this.Visibility = System.Windows.Visibility.Visible;
            this.Topmost = true;
        }

        /// <summary>
        /// Get Guest-Status and update GUI.
        /// </summary>
        public void updateStatus()
        {
            try
            {
                /************************************************
                * Setup interprocess-connection to service.
                * */
                ChannelFactory<IServiceStatus> tcpFactory = new ChannelFactory<IServiceStatus>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:" + oSettings.ControlPort + "/"));

                IServiceStatus tcpProxy = tcpFactory.CreateChannel();

                // Get current status.
                CurrentStatus = tcpProxy.getCurrentStatus();
            }
            catch (Exception ex)
            {
                CurrentStatus = 0;
                //MessageBox.Show(ex.Message);
            }

            // Update GUI.
            updateGUI();
        }

        /// <summary>
        /// Update GUI.
        /// </summary>
        private void updateGUI()
        {
            try
            {
                m_NotifyIcon.Icon = new System.Drawing.Icon(VBoxService.Settings.getServiceBaseDir() + "unknown.ico");
                imgStatus.Source = new BitmapImage(new Uri(VBoxService.Settings.getServiceBaseDir() + "unknown.png", UriKind.RelativeOrAbsolute));
                btnExit.Content = Strings.T_Exit;

                /************************************************
                * Get Current Status.
                * */
                switch (CurrentStatus)
                {
                    case 0:     // Powered Off
                        lblGuestStatus.Content = Strings.T_Status_Off;
                        lblGuestStatus.Foreground = Brushes.Black;
                        lblGuestStatus.FontWeight = FontWeights.Normal;
                        m_NotifyIcon.Icon = new System.Drawing.Icon(VBoxService.Settings.getServiceBaseDir() + "off.ico");
                        imgStatus.Source = new BitmapImage(new Uri(VBoxService.Settings.getServiceBaseDir() + "off.png", UriKind.RelativeOrAbsolute));
                        break;
                    case 1:     // Saved to disk
                        lblGuestStatus.Content = Strings.T_Status_Saved;
                        lblGuestStatus.Foreground = Brushes.DarkGreen;
                        lblGuestStatus.FontWeight = FontWeights.Bold;
                        m_NotifyIcon.Icon = new System.Drawing.Icon(VBoxService.Settings.getServiceBaseDir() + "paused.ico");
                        imgStatus.Source = new BitmapImage(new Uri(VBoxService.Settings.getServiceBaseDir() + "pause.png", UriKind.RelativeOrAbsolute));
                        break;
                    case 2:     // Paused via VBoxManage
                        lblGuestStatus.Content = Strings.T_Status_Paused;
                        lblGuestStatus.Foreground = Brushes.Orange;
                        lblGuestStatus.FontWeight = FontWeights.Bold;
                        m_NotifyIcon.Icon = new System.Drawing.Icon(VBoxService.Settings.getServiceBaseDir() + "paused.ico");
                        imgStatus.Source = new BitmapImage(new Uri(VBoxService.Settings.getServiceBaseDir() + "pause.png", UriKind.RelativeOrAbsolute));
                        break;
                    case 6:     // Running/Resuming
                        lblGuestStatus.Content = Strings.T_Status_Running;
                        lblGuestStatus.Foreground = Brushes.Green;
                        lblGuestStatus.FontWeight = FontWeights.Bold;
                        m_NotifyIcon.Icon = new System.Drawing.Icon(VBoxService.Settings.getServiceBaseDir() + "running.ico");
                        imgStatus.Source = new BitmapImage(new Uri(VBoxService.Settings.getServiceBaseDir() + "running.png", UriKind.RelativeOrAbsolute));
                        break;
                    default:
                        break;
                }

                // Get active mounts.
                getMounts();

                // Get possible power-modes.
                loadPowerModes();

                // Initialize ODD-Control.
                loadODControl();

                // Update Controls.
                this.UpdateLayout();
            }
            catch (Exception ex)
            {
                MessageBox.Show(Strings.E_GUIUpdate + ex.Message, Strings.T_Error, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// Check active mounts.
        /// </summary>
        private void getMounts()
        {
            spMounts.Children.Clear();

            // Get ODD-Mount.
            try
            {
                ChannelFactory<IServiceStatus> tcpFactory = new ChannelFactory<IServiceStatus>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:" + oSettings.ControlPort + "/"));

                IServiceStatus tcpProxy = tcpFactory.CreateChannel();

                string sMountPoint = tcpProxy.getDriveStatus(oSettings.ODDController, oSettings.ODDPort, oSettings.ODDDevice);
                Label lblMountPoint = new Label();
                lblMountPoint.Content = sMountPoint;

                spMounts.Children.Add(lblMountPoint);
                /*
                sMountPoint = String.Empty;
                sMountPoint = tcpProxy.getDriveStatus(oSettings.HDDController, "0", "0");
                if (sMountPoint != string.Empty)
                {
                    lblMountPoint = new Label();
                    lblMountPoint.Content = sMountPoint;

                    spMounts.Children.Add(lblMountPoint);
                }*/
            }
            catch (Exception ex)
            {
                CurrentStatus = 0;
                //MessageBox.Show(ex.Message);
            }

        }

        /// <summary>
        /// Initialize ODD-Controls.
        /// </summary>
        private void loadODControl()
        {
            btnMountISO.Content = Strings.T_OD_ISO;
            btnMountDrive.Content = Strings.T_OD_Drive;
        }

        /// <summary>
        /// Load available powermodes.
        /// </summary>
        private void loadPowerModes()
        {
            /**************************************************
             * Setup Powermode-Selector.
             * */
            cmbTargetPowerMode.Items.Clear();

            PowerMode mPowerOff = new PowerMode(0);
            PowerMode mPowerSaved = new PowerMode(1);
            PowerMode mPowerPaused = new PowerMode(2);
            PowerMode mPowerRunning = new PowerMode(6);

            cmbTargetPowerMode.Items.Add(mPowerOff);
            cmbTargetPowerMode.Items.Add(mPowerSaved);
            cmbTargetPowerMode.Items.Add(mPowerPaused);
            cmbTargetPowerMode.Items.Add(mPowerRunning);


            /**************************************************
             * Select current Powermode in cmbPowermode.
             * */
            switch (CurrentStatus)
            {
                case 0:
                    cmbTargetPowerMode.SelectedIndex = 0;
                    break;
                case 1:
                    cmbTargetPowerMode.SelectedIndex = 1;
                    break;
                case 2:
                    cmbTargetPowerMode.SelectedIndex = 2;
                    break;
                case 6:
                    cmbTargetPowerMode.SelectedIndex = 3;
                    break;
                default:
                    break;
            }

            btnSetPowerMode.Content = Strings.T_SetPowerMode;
        }

        /// <summary>
        /// Send Powermode-Change command.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSetPowerMode_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                int iTargetMode = ((PowerMode)cmbTargetPowerMode.SelectedItem).Mode;

                ChannelFactory<IServiceStatus> tcpFactory = new ChannelFactory<IServiceStatus>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:" + oSettings.ControlPort + "/"));

                IServiceStatus tcpProxy = tcpFactory.CreateChannel();

                if (tcpProxy.setPowerMode(iTargetMode))
                {
                    System.Threading.Thread.Sleep(3000);
                    updateStatus();
                }
                else
                    MessageBox.Show(Strings.E_SetPowerModeError, Strings.T_Error, MessageBoxButton.OK, MessageBoxImage.Error);
            }
            catch (TimeoutException tex)
            {
                CurrentStatus = 0;
                MessageBox.Show(String.Format(Strings.E_ServiceNotResponding, oSettings.ControlPort), Strings.T_ServiceNotResponding, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            catch (Exception ex)
            {
                CurrentStatus = 0;
                MessageBox.Show(ex.Message);
            }

            //updateStatus();
        }

        /// <summary>
        /// Mount selected ISO-file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMountISO_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                int iTargetMode = ((PowerMode)cmbTargetPowerMode.SelectedItem).Mode;

                ChannelFactory<IServiceStatus> tcpFactory = new ChannelFactory<IServiceStatus>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:" + oSettings.ControlPort + "/"));

                IServiceStatus tcpProxy = tcpFactory.CreateChannel();

                if (tcpProxy.mountDVD(false, txtODPath.Text))
                {
                    MessageBox.Show(String.Format(Strings.T_OD_Mounted_Description, txtODPath.Text, oSettings.ODDController + ":" + oSettings.ODDPort + ":" + oSettings.ODDDevice), Strings.T_OD_Mounted, MessageBoxButton.OK, MessageBoxImage.Information);
                }
                else
                    MessageBox.Show(Strings.E_OD_Mount_Error, Strings.T_Error, MessageBoxButton.OK, MessageBoxImage.Error);
            }
            catch (TimeoutException tex)
            {
                CurrentStatus = 0;
                MessageBox.Show(String.Format(Strings.E_ServiceNotResponding, oSettings.ControlPort), Strings.T_ServiceNotResponding, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            catch (Exception ex)
            {
                CurrentStatus = 0;
                MessageBox.Show(ex.Message);
            }

            getMounts();
        }

        /// <summary>
        /// Mount physical DVD-Drive.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMountDrive_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                int iTargetMode = ((PowerMode)cmbTargetPowerMode.SelectedItem).Mode;

                ChannelFactory<IServiceStatus> tcpFactory = new ChannelFactory<IServiceStatus>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:" + oSettings.ControlPort + "/"));

                IServiceStatus tcpProxy = tcpFactory.CreateChannel();

                string sDriveLetter = txtODPath.Text.Substring(0, 1);

                if (tcpProxy.mountDVD(true, sDriveLetter))
                {
                    MessageBox.Show(String.Format(Strings.T_OD_Mounted_Description, txtODPath.Text.Substring(0, 1) + ":", oSettings.ODDController + ":" + oSettings.ODDPort + ":" + oSettings.ODDDevice), Strings.T_OD_Mounted, MessageBoxButton.OK, MessageBoxImage.Information);
                }
                else
                    MessageBox.Show(Strings.E_OD_Mount_Error, Strings.T_Error, MessageBoxButton.OK, MessageBoxImage.Error);
            }
            catch (TimeoutException tex)
            {
                CurrentStatus = 0;
                MessageBox.Show(String.Format(Strings.E_ServiceNotResponding, oSettings.ControlPort), Strings.T_ServiceNotResponding, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            catch (Exception ex)
            {
                CurrentStatus = 0;
                MessageBox.Show(ex.Message);
            }

            getMounts();
        }

        /// <summary>
        /// Start ISO-Browser for ODD-Controls.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnBrowseISO_Click(object sender, RoutedEventArgs e)
        {
            if (dlgBrowseISO.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                txtODPath.Text = dlgBrowseISO.FileName;
            }
        }

        private void Window_StateChanged(object sender, EventArgs e)
        {
            if (this.WindowState == System.Windows.WindowState.Normal)
            {
                this.Visibility = System.Windows.Visibility.Visible;
            }
            else if (this.WindowState == System.Windows.WindowState.Maximized)
            {
                this.WindowState = System.Windows.WindowState.Normal;
                this.Visibility = System.Windows.Visibility.Visible;
            }
            else if (this.WindowState == System.Windows.WindowState.Minimized)
            {
                this.Visibility = System.Windows.Visibility.Hidden;
            }
        }

        private void btnAbout_Click(object sender, RoutedEventArgs e)
        {
            About dlgAbout = new About();
            dlgAbout.Topmost = true;
            dlgAbout.Show();
        }

        private void btnExit_Click(object sender, RoutedEventArgs e)
        {
            Environment.Exit(0);
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            m_NotifyIcon.Visible = false;
            m_NotifyIcon.Dispose();
        }

        private void btnRefresh_Click(object sender, RoutedEventArgs e)
        {
            updateStatus();
        }
    }
}
